let dao = require("./dao")
let getKey = require("./rediskeyMaker.js")
let {mapSeries, waterfall} = require("async")


async function addGroup(domain, gid, agents) {
    let k = getKey({domain, group: {id: gid, all: true}})
    let v = await dao.getKeys(k + "*")
    return new Promise((resolve, reject) => {
        mapSeries(v,
            (item, cb) => {
                console.log("11111111", item)
                dao.deleteKey(item).then(v => cb())
                console.log("222222")
            },
            (err, rsts) => {
                agents.map(agentId => {
                    dao.checkAgentOnline(domain, agentId).then(v => {
                        if (!v) return
                        dao.addAgentToGroup(domain, gid, agentId)
                        dao.addGroupsToAgent(domain, agentId, [gid])
                    })
                })
                return resolve({msg: "添加客服组成功"})
            }
        )
    })
}

async function deleteGroup(domain, gids) {
    return new Promise((resolve, reject) => {
        mapSeries(gids,
            (gid, cb) => {
                dao.getAgentsFromGroup(domain, gid).then(v => {
                    console.log("getAgentsFromGroup", gid, v)
                    v.map(agentId => dao.deleteGroupFromAgent(domain, agentId, gid))
                    let k = getKey({domain, group: {id: gid, all: true}})
                    dao.getKeys(k + "*").then(v =>
                        v.map(k => dao.deleteKey(k))
                    )
                    cb()
                })
            },
            (err, rsts) => {
                return resolve({msg: "删除客服组成功:" + gids})
            }
        )
    })
}

async function updateGroup(domain, gid, adds, dels) {
    if ((!dels || dels.length === 0) && (!adds || adds.length === 0)) {
        return {msg: "客服组无更新"}
    }

    let v = await dao.getAgentsFromGroup(domain, gid)
    let aas = v && v.length > 0 ? v : []
    console.log("updateGroup.getAgentsFromGroup:", gid, aas)

    console.log("updateGroup.dels start:", dels)
    return new Promise((resolve, reject) => {
        mapSeries(dels,
            function (agentId, cb) {
                if (!aas || aas.length === 0 || aas.indexOf(agentId) === -1) {
                    dao.deleteGroupFromAgent(domain, agentId, gid).then(v => cb(null, agentId))
                }
                else {
                    let index = aas.indexOf(agentId)
                    aas.splice(index, 1)
                    dao.deleteAgentFromGroup(domain, gid, agentId).then(v => {
                        dao.deleteGroupFromAgent(domain, agentId, gid).then(v => cb(null, agentId))
                    })
                }

            }, function (err, results) {
                console.log("updateGroup.del done, ", err, results)


                console.log("updateGroup.add start:", adds)
                let newOnlineAgent = []
                mapSeries(adds,
                    function (agentId, cb) {
                        dao.checkAgentOnline(domain, agentId).then(v => {
                            if (!v) return cb(null, '')
                            newOnlineAgent.push(agentId)
                            if (aas && aas.indexOf(agentId) === -1) {
                                aas.push(agentId)
                                dao.addAgentToGroup(domain, gid, agentId).then(v => {
                                    dao.addGroupsToAgent(domain, agentId, [gid]).then(v => cb(null, agentId))
                                })
                            } else {
                                dao.addGroupsToAgent(domain, agentId, [gid]).then(v => cb(null, agentId))
                            }
                        })
                    }, function (err, results) {
                        console.log("updateGroup.add done, ", err, results)


                        if (newOnlineAgent.length > 0) return resolve({msg: "更新客服组成功"})
                        if (!aas || aas.length === 0) {
                            dao.removeServiceRequest(domain, gid)
                            return resolve({msg: "更新客服组成功: 已清空队列"})
                        }
                        let oldAgent = aas.filter(v => newOnlineAgent.indexOf(v) === -1)
                        dealQueueWhenAgentsChange(domain, oldAgent, gid).then(haveOnline => {
                            if (haveOnline) return resolve({msg: "更新客服组成功"})
                            else return resolve({msg: "更新客服组成功: 已清空队列"})
                        })
                    }
                )
            }
        )
    })
}

async function offlineAgent(domain, agentId) {
    let online = await dao.checkAgentOnline(domain, agentId)
    if (!online) return {msg: "客服状态无变化: 已下线", agentId}

    let onlined = await dao.setAgentOnline(domain, agentId, false)
    if (!onlined) return {msg: "客服状态无变化: 已下线", agentId}
    let status = await dao.getAgentStatus(domain, agentId)
    let requestId = status ? status : ""
    if (requestId) return {msg: "客服下线成功", requestId, agentId}

    let gids = await dao.getGroupFromAgent(domain, agentId)
    if (!gids || gids.length === 0) return {msg: "客服下线成功：无客服组", requestId, agentId}

    return new Promise((resolve, reject) => {
        mapSeries(gids,
            (gid, cb) => {
                dao.getServiceRequests(domain, gid).then(srs => {
                    if (!srs || srs.length === 0) return cb()
                    dao.getAgentsFromGroup(domain, gid).then(agents => {
                        dealQueueWhenAgentsChange(domain, agents, gid).then(haveOnline => {
                            return cb(null, haveOnline ? "" : gid)
                        })
                    })
                })
            }, (err, dealedQueue) => {
                return resolve({msg: "客服下线成功，已清空队列的客服组: " + dealedQueue, requestId, agentId})
            }
        )
    })
}

async function onlineAgent(domain, agentId, groups) {
    await dao.addDomain(domain)
    let update = await updateAgent(domain, agentId, groups, true)
    await dao.setAgentOnline(domain, agentId, true)
    let status = await dao.getAgentStatus(domain, agentId)
    let lastRequest = status ? status : ""
    return {msg: "客服上线成功; " + update.msg, lastRequest}
}

async function clearAgentStatus(domain, agentId) {
    let status = await dao.getAgentStatus(domain, agentId)
    let lastRequest = status ? status : ""
    await dao.setAgentStatus(domain, agentId, null)
    await dao.deleteWorkingAgent(domain, agentId)
    return {msg: "客服清除状态成功", lastRequest}
}

async function setAgentStatus(domain, agentId, requestId) {
    await dao.setLastDistributeTime(domain, agentId, new Date().getTime())
    await dao.setAgentStatus(domain, agentId, requestId)
    await dao.addWorkingAgent(domain, agentId)
    return {msg: "客服设置状态成功"}
}

async function updateAgent(domain, agentId, gids, online) {
    if (!online) {
        online = await dao.checkAgentOnline(domain, agentId)
        if (!online) return {msg: "该客服未曾登录，无需更新"}
    }

    let group = await dao.getGroupFromAgent(domain, agentId)
    let oldGids = group && group.length > 0 ? group : []
    let gidsNonEmpty = gids && gids.length > 0
    let adds = gidsNonEmpty ? gids.filter(x => oldGids.indexOf(x) === -1) : []
    let dels = gidsNonEmpty ? oldGids.filter(x => gids.indexOf(x) === -1) : oldGids


    if (dels && dels.length > 0) {
        await new Promise((resolve, reject) => {
            mapSeries(dels,
                (gid, cb) => {
                    new Promise((resolve, reject) => {
                        let mission = []
                        let index, lda, mAgents
                        mission.push(function (cb) {
                            dao.getAgentsFromGroup(domain, gid).then(v => {
                                mAgents = v
                                if (!mAgents || mAgents.length === 0) return cb('updateAgent del true:' + gid)
                                index = mAgents.indexOf(agentId)
                                if (index === -1) return cb('updateAgent del true:' + gid)
                                dao.deleteAgentFromGroup(domain, gid, agentId).then(v => {
                                    return cb()
                                })
                            })
                        })
                        mission.push(function (cb) {
                            mAgents.splice(index, 1)
                            if (!mAgents || mAgents.length === 0) {
                                dao.removeServiceRequest(domain, gid).then(v => {
                                    return cb("updateAgent del 已清空队列:" + gid)
                                })
                            } else {
                                dealQueueWhenAgentsChange(domain, mAgents, gid).then(haveOnline => {
                                    if (!haveOnline) return cb(true, "updateAgent 已清空队列:" + gid)
                                    return cb("updateAgent del:" + gid)
                                })
                            }
                        })
                        waterfall(mission, function (errInfo, result) {
                            resolve(errInfo)
                        });
                    }).then(info => {
                        cb(null, info)
                    })
                },
                (err, rsts) => {
                    console.log("agentId: " + agentId + " " + rsts)
                    resolve(rsts)
                })
        })
    }

    await dao.removeAgentGroups(domain, agentId)
    if (gidsNonEmpty) await dao.addGroupsToAgent(domain, agentId, gids)

    if (adds && adds.length > 0) {
        await new Promise((resolve, reject) => {
            mapSeries(adds,
                (gid, cb) => {
                    if (!gid) return cb()
                    dao.addAgentToGroup(domain, gid, agentId).then(v => {
                        return cb(null, "updateAgent add:" + gid)
                    })
                },
                (err, rsts) => {
                    console.log("agentId: " + agentId + " " + rsts)
                    resolve()
                })
        })
    }

    return {msg: "更新客服成功"}
}

async function deleteRequest(domain, id, newId, requestGids, agentId) {
    let info = {msg: "会话已分配", distribute: true, agentId, requestId: id}
    for (let gid of requestGids) {
        let v = await dao.getServiceRequests(domain, gid)
        let index = v && v.length > 0 ? v.indexOf(id) : -1

        if (index > -1) {
            await dao.deleteServiceRequest(domain, gid, id)
            info = {msg: "会话已删除", distribute: false, agentId, requestId: id}
        }
    }

    if (!agentId || !info.distribute) return info

    let status = await dao.getAgentStatus(domain, agentId)
    if (!status || status !== id) {
        info.msg += "; 客服status与requestId不一致：" + status + ";"
        return info
    }
    if (newId) {
        await dao.setAgentStatus(domain, agentId, newId)
        info.msg += "; 客服切换至下一个呼叫成功;"
        return info
    }
    await dao.setAgentStatus(domain, agentId, null)
    let del = await dao.deleteWorkingAgent(domain, agentId)
    if (!del) {
        info.msg += "; 客服切换至空闲状态失败;"
        return info
    }

    let online = await dao.checkAgentOnline(domain, agentId)
    if (online) {
        info.msg += "; 客服状态正常;"
        return info
    }
    let gids = await dao.getGroupFromAgent(domain, agentId)
    return new Promise((resolve, reject) => {
        if (!gids || gids.length === 0) {
            info.msg += "; 客服下线成功：无客服组;"
            return resolve(info)
        }
        mapSeries(gids,
            (gid, cb) => {
                dao.getServiceRequests(domain, gid).then(srs => {
                    if (!srs || srs.length === 0) return cb()
                    dao.getAgentsFromGroup(domain, gid).then(agents => {
                        dealQueueWhenAgentsChange(domain, agents, gid).then(haveOnline => {
                            return cb(null, haveOnline ? "" : gid)
                        })
                    })
                })
            }, (err, dealedQueue) => {
                info.msg += "; 客服下线成功：已清空队列的客服组: " + dealedQueue + ";"
                return resolve(info)
            }
        )
    })

}

async function takeRequest(domain, agentId) {
    let online = await dao.checkAgentOnline(domain, agentId)
    if (!online) return {msg: "该客服已下线，无需分配请求", request: "", agentId}
    let status = await dao.getAgentStatus(domain, agentId)
    if (status) return {msg: "该客服正在会话中", request: "", agentId}
    let notWorking = await dao.addWorkingAgent(domain, agentId)
    if (!notWorking) return {msg: "该客服正在服务中", request: "", agentId}

    let groups = await dao.getGroupFromAgent(domain, agentId)
    console.log("takeRequest groups:", groups)
    return new Promise(async (resolve, reject) => {
        for (let gid of groups) {
            let queue = await dao.getServiceRequests(domain, gid);
            if (queue && queue.length > 0) {
                for (let sr of queue) {
                    let online = await dao.checkAgentOnline(domain, agentId)
                    if (!online) return resolve({msg: "该客服已下线，无需分配请求", request: "", agentId})
                    let srGroups = await dao.getRequestGroups(domain, sr)
                    if (srGroups && srGroups.length > 0) {
                        let setResult = await dao.setRequestGroups(domain, sr, null)
                        if (setResult > 0) {
                            for (let srGroup of srGroups)
                                await dao.deleteServiceRequest(domain, srGroup, sr)
                            await dao.setAgentStatus(domain, agentId, sr)
                            return resolve({msg: "获取成功", request: sr, agentId})
                        }
                    }
                }
            }
        }
        await dao.deleteWorkingAgent(domain, agentId)
        return resolve({msg: "无请求分配", request: "", agentId});
    })
}

async function requestWaiting(domain, id, gids) {
    let count = -1
    for (let gid of gids) {
        let queue = await dao.getServiceRequests(domain, gid)
        if (queue && queue.indexOf(id) !== -1) {
            let tempCount = queue.indexOf(id) + 1
            if (count < 0 || count > tempCount)
                count = tempCount;
        }
    }
    return {msg: "获取排队数成功", count}
}

async function addRequest(domain, id, gids, agentId, advance) {
    let result = await distributeAgent(domain, gids, agentId)
    if (result) {
        await dao.setLastDistributeTime(domain, result, new Date().getTime())
        await dao.setAgentStatus(domain, result, id)
        return {msg: "分配成功", agent: result}
    }
    else {
        await dao.setRequestGroups(domain, id, gids)
        for (let gid of gids) {
            await dao.addServiceRequest(domain, gid, id, advance)
        }
        return {msg: "进入队列", agent: ""}
    }
}

async function distributeAgent(domain, gids, agentId) {
    if (agentId) {
        let online = await dao.checkAgentOnline(domain, agentId)
        if (online) {
            let status = await dao.getAgentStatus(domain, agentId)
            if (!status) {
                let add = await dao.addWorkingAgent(domain, agentId)
                if (add) {
                    return agentId
                }
            }
        }
    }
    return getDistributeAgent(domain, gids, agentId)
}

async function getDistributeAgent(domain, gids) {
    let result = null
    let mAgents = [];
    for (let gid of gids) {
        let tempAgents = await dao.getAgentsFromGroup(domain, gid);
        mAgents = [...new Set([...mAgents, ...tempAgents])];
    }
    if (mAgents.length === 0) return result

    let agentsTime = await dao.getLastDistributeTime(domain, mAgents);
    let agents = [];
    for (let i in mAgents)
        agents.push({id: mAgents[i], time: agentsTime[i]});
    agents.sort((a, b) => {
        let aTime = a.time ? parseInt(a.time) : 0;
        let bTime = b.time ? parseInt(b.time) : 0;
        if (aTime > bTime) return 1;
        else return -1;
    });

    for (let i in agents) {
        let online = await dao.checkAgentOnline(domain, agents[i].id)
        if (online) {
            let status = await dao.getAgentStatus(domain, agents[i].id)
            if (!status) {
                let add = await dao.addWorkingAgent(domain, agents[i].id)
                if (add) {
                    result = agents[i].id
                    break
                }
            }
        }
    }
    return result
}

async function getFreeAgents(domain, gids) {
    let result = []
    for (let gid of gids) {
        let agents = await dao.getAgentsFromGroup(domain, gid)
        if (agents && agents.length > 0) {
            for (let i in agents) {
                if (result.indexOf(agents[i]) < 0) {
                    let online = await dao.checkAgentOnline(domain, agents[i])
                    if (online) {
                        let status = await dao.getAgentStatus(domain, agents[i])
                        if (!status) {
                            result.push(agents[i])
                        }
                    }
                }
            }
        }
    }
    return result
}

async function checkFreeAgent(domain, agent) {
    let result = false;
    let online = await dao.checkAgentOnline(domain, agent);
    if (online) {
        let status = await dao.getAgentStatus(domain, agent);
        if (!status) {
            result = true;
        }
    }
    return result;
}

function dealQueueWhenAgentsChange(domain, agents, gid) {
    return new Promise((resolve, reject) => {
        if (!agents || agents.length === 0) return resolve(true)
        mapSeries(agents,
            (agentId, cb) => {
                dao.checkAgentOnline(domain, agentId).then(online => {
                    if (!online) return cb()
                    dao.getAgentStatus(domain, agentId).then(status => {
                        if (!status) return cb(null, true)
                        return cb()
                    })
                })
            }, (err, haveOnline) => {
                if (!haveOnline) dao.removeServiceRequest(domain, gid)
                return resolve(haveOnline)
            }
        )
    })
}


module.exports = {
    addGroup,
    deleteGroup,
    updateGroup,

    onlineAgent,
    offlineAgent,
    updateAgent,
    clearAgentStatus,
    setAgentStatus,

    addRequest,
    takeRequest,
    deleteRequest,

    requestWaiting,
    getFreeAgents,
    checkFreeAgent
}